#pragma once 
#include "mut.h"
#include "mutcamera.h"
#include "mutresmanager.h"
#include "mutsky.h"
#include "mutbound.h"
#include "muttree.h"

class CMUTMapWorld;
const int maxGrassNum = 200;
class CMUTGrass{
public:
	int numGrass;
	LPDIRECT3DVERTEXBUFFER9 vb;
	LPDIRECT3DINDEXBUFFER9 ib;
	LPVOID vertsVoid;
	LPVOID trisVoid;
	CMUTTexture* atex;
	CMUTTexture* dtex;
	CMUTGrass() : numGrass(0), vb(0), ib(0), atex(0), dtex(0) {}
	HRESULT Create( HANDLE hEvent, int gnum );
	void InitData( D3DXVECTOR3 bias, D3DXVECTOR3* pts );
	void Render( LPDIRECT3DDEVICE9 pDevice );
	void Release( HANDLE hEvent=0 );
};
class CMUTWater{
public:
	LPDIRECT3DVERTEXBUFFER9 vb;
	LPDIRECT3DINDEXBUFFER9 ib;
	CMUTWater(): vb(0), ib(0) {}
	HRESULT Create();
	void InitData( D3DXVECTOR3 minPos, D3DXVECTOR3 maxPos );
	void Render( LPDIRECT3DDEVICE9 pDevice );
	void Release();
};

// vnum = MAPCHUNK_VSIZE^2 + (MAPCHUNK_VSIZE-1)^2
const int MAPCHUNK_VSIZE = 9;
const float MAPCHUNK_SIZE = 200.0f;
const float MAP_HEIGHTSCALE = 20.0f;
const int MAPCHUNK_BLENDSIZE = 64;
const int MAPCHUNK_INDEXLOD2FSTART = ( MAPCHUNK_VSIZE-1 )*( MAPCHUNK_VSIZE-1 )*4;
const int MAPCHUNK_INDEXLOD2FNUM = ( MAPCHUNK_VSIZE-1 )*( MAPCHUNK_VSIZE-1 )*2;

const int MAPTILE_SIZE = 16;
const float MAPTILE_CHUNKBIAS = MAPCHUNK_SIZE*(MAPCHUNK_VSIZE-1);
const int MAPCHUNK_HEIGHTMAP_SIZE = 2*MAPCHUNK_VSIZE - 1;
const int MAPTILE_HEIGHTMAP_SIZE = MAPTILE_SIZE * (MAPCHUNK_HEIGHTMAP_SIZE-1) + 1;

const int MAPWORLD_CACHE = 16;
const float MAPWORLD_TILEBIAS = MAPTILE_CHUNKBIAS*MAPTILE_SIZE;

class CMUTMapChunk{
public:
	CMUTWater water;
	CMUTGrass grass;
	CMUTTreeSet treeSet;
	CMUTBoundingBox box;
	LPVOID pVertexVoid;
	LPVOID pIndexVoid;
	int gnum;
	int tnum;
	bool grassed;
	bool treed;
	bool watered;
	bool visible;
	bool lod;
	int vnum;
	int fnum;
	LPDIRECT3DVERTEXBUFFER9 vb;
	LPDIRECT3DINDEXBUFFER9 ib;
	CMUTTexture* blend;
	CMUTTexture* tex[4];
	CMUTMapChunk() : gnum(0), tnum(0), vnum(0), fnum(0), vb(0), ib(0), lod(false), visible(true), grassed(true), treed(true), watered(false) {
		ZeroMemory( tex, sizeof( tex ) );
		blend = 0;
	}
	HRESULT Create( WCHAR* blendfn, HANDLE hEvent, int gnum, int tnum );
	void Culling( D3DXPLANE* p );
	//void Lod( D3DXVECTOR cpos );
	void Release();
	void Render( LPDIRECT3DDEVICE9 pDevice );
	void RenderGrass( LPDIRECT3DDEVICE9 pDevice );
	void RenderTreeTrunk();
	void RenderTreeLeaf();
	void RenderWater();
	void InitDefaultVertexData( CMUTMapWorld* world, D3DXVECTOR2 uvblendBias, D3DXVECTOR3 posBias, BYTE tiles[MAPTILE_HEIGHTMAP_SIZE][MAPTILE_HEIGHTMAP_SIZE], float height[MAPTILE_HEIGHTMAP_SIZE][MAPTILE_HEIGHTMAP_SIZE], POINT bias );
	void InitDefaultIndexData();
	void InitGrass( D3DXVECTOR3 bias, D3DXVECTOR3* pts );
};

struct THREADPARAM{
	CMUTMapWorld* world;
	HANDLE* pSingleTileEvent;
};
class CMUTMapTile{
public:
	THREADPARAM threadParam;
	HANDLE hResEvent;
	bool bLoading;
	bool bEmpty;
	POINT coord;
	CMUTTexture* blend;
	CMUTMapChunk chunks[ MAPTILE_SIZE ][ MAPTILE_SIZE ];
	BYTE heightmap[ MAPTILE_HEIGHTMAP_SIZE ][ MAPTILE_HEIGHTMAP_SIZE ];
	float fheightmap[ MAPTILE_HEIGHTMAP_SIZE ][ MAPTILE_HEIGHTMAP_SIZE ];
	CMUTMapTile();
	HRESULT Create( POINT c, HANDLE hHeightFile );
	void Culling( D3DXPLANE* p );
	//void Lod( D3DXVECTOR3 cpos );
	void Render( LPDIRECT3DDEVICE9 pDevice );
	void RenderGrass( LPDIRECT3DDEVICE9 pDevice );
	void RenderTreeTrunk();
	void RenderTreeLeaf();
	void RenderWater();
	void InitVertexData( CMUTMapWorld* world );
	void FixLeftEdge( CMUTMapTile* pLeftTile );
	void FixUpEdge( CMUTMapTile* pUpTile );
	inline float GetHeight( int hvert, int wvert, float hLerp, float wLerp );
	void Release();
};

class CMUTMapWorld{
public:
	HANDLE hSingleTileEvent;
	LPDIRECT3DTEXTURE9 pDepthTex;
	LPDIRECT3DTEXTURE9 pDepthTexSmall;
	LPDIRECT3DTEXTURE9 pScreenTex;
	LPDIRECT3DSURFACE9 pDepthStencil;
	CMUTSky sky;
	CMUTMapTile tileCache[ MAPWORLD_CACHE ];
	int usedCache[ MAPWORLD_CACHE ];
	CMUTMapTile* tileShow[3][3];
	CMUTMapWorld();
	HRESULT LoadMapTile( POINT coord, CMUTMapTile& tile );
	HRESULT Create();
	void Culling( D3DXMATRIX m /*frustum*/ );
	void Render( CMUTCamera& c );
	void RenderDepth( CMUTCamera& c, D3DXMATRIX matLightView, D3DXMATRIX matLightOrtho, D3DXMATRIX matLightOrthoSmall );
	void UpdateTiles( CMUTCamera& c );
	void FixTileEdge();
	float GetHeight( float x, float z );
	void Release();
};